package com.exrobot.module.rbt.service.iben;

import cn.hutool.core.util.IdUtil;
import com.anji.captcha.util.Base64Utils;
import com.exrobot.framework.common.util.http.HttpUtils;
import com.exrobot.framework.common.util.json.JsonUtils;
import com.exrobot.module.rbt.constant.IbenApiPathConsts;
import com.exrobot.module.rbt.dal.iben.auth.IbenAuthDTO;
import com.exrobot.module.rbt.dal.iben.auth.IbenCommonResult;
import com.exrobot.module.rbt.dal.iben.map.*;
import com.exrobot.module.rbt.dal.iben.task.*;
import com.exrobot.module.rbt.dal.iben.robot.OpenRobotDTO;
import com.exrobot.module.rbt.dal.iben.robot.OpenRobotDetail;
import com.exrobot.module.rbt.dal.iben.robot.OpenRobotDetailDTO;
import com.exrobot.module.rbt.dal.iben.robot.OpenRobotQuery;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Service
@Validated
public class RobotIbenServiceImpl implements RobotIbenService {

    private String version = "0.1.0";
    /**
     * 授权认证
     * HashMap = { tenantCode: '企业编码'}
     * */
    @Override
    public IbenCommonResult<IbenAuthDTO> authAppSecret(HashMap<String,String> hashMap) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_AUTH_SECRET,hashMap);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<IbenAuthDTO>>(){});
    }

    /**
     * 取消任务
     * */
    @Override
    public IbenCommonResult<OpenTaskExecDTO> cancelTask(OpenTaskCancel taskCancel) {
        String resultBody = getResultBody(IbenApiPathConsts.CANCEL_TASK,taskCancel);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenTaskExecDTO>>(){});
    }

    /**
     * 获取任务列表
     * */
    @Override
    public IbenCommonResult<OpenTaskRecordDTO> getTaskList(OpenTaskExecQuery hashMap) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_TASK_LIST,hashMap);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenTaskRecordDTO>>(){});
    }

    /**
     * 新建任务
     * */
    @Override
    public IbenCommonResult<IbenAuthDTO> createExecTask(OpenTaskExecCreate taskExecCreate) {
        String resultBody = getResultBody(IbenApiPathConsts.CREATE_TASK,taskExecCreate);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<IbenAuthDTO>>(){});
    }

    /**
     * 获取任务详情
     * */
    @Override
    public IbenCommonResult<OpenTaskRecordDetailDTO> taskDetails(OpenTaskExecDetail taskExecDetail) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_TASK_DETAILS,taskExecDetail);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenTaskRecordDetailDTO>>(){});
    }

    /**
     * 获取地图信息
     * */
    @Override
    public IbenCommonResult<OpenMapDetailDTO> getMapDetail(OpenMapDetail mapDetail) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_MAP_DETAIL,mapDetail);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenMapDetailDTO>>(){});
    }

    /**
     * 获取地图列表
     *
     * */
    @Override
    public IbenCommonResult<OpenMapDTO> getMaps(OpenMapQuery mapQuery) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_MAP_LIST,mapQuery);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenMapDTO>>(){});
    }
    /**
     * 获取点位详情
     *
     * */
    @Override
    public IbenCommonResult<PointDetailDTO> getPointDetail(OpenPointDetail pointDetail) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_POINT_DETAIL,pointDetail);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<PointDetailDTO>>(){});
    }
    /**
     * 获取点位列表
     * */
    @Override
    public IbenCommonResult<PointDetailDTO> getPoints(OpenMapPointsQuery mapPointsQuery) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_POINT_LIST,mapPointsQuery);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<PointDetailDTO>>(){});
    }
    /**
     * 获取机器人列表
     * */
    @Override
    public IbenCommonResult<OpenRobotDTO> getRobots(OpenRobotQuery robotQuery) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_ROBOT_LIST,robotQuery);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenRobotDTO>>(){});
    }
    /**
     * 获取机器人详情（机器人版本信息及在线状态，运行状态）
     * */
    @Override
    public IbenCommonResult<OpenRobotDetailDTO> queryDetail(OpenRobotDetail robotDetail) {
        String resultBody = getResultBody(IbenApiPathConsts.GET_ROBOT_DETAIL,robotDetail);
        return JsonUtils.parseObjectQuietly(resultBody, new TypeReference<IbenCommonResult<OpenRobotDetailDTO>>(){});
    }


    private String getResultBody(String api,Object object) {
        if(api.isBlank()) {
            return "";
        }
        String url = IbenApiPathConsts.IBEN_BASE_URL+String.format(api,version);
        String requestBody = null;
        try {
            requestBody = convertToFormUrlEncoded(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        Long timestamp = System.currentTimeMillis();
        String requestId = IdUtil.simpleUUID();
        String sign = generateSignature(timestamp,requestId);
        return HttpUtils.post(url,getHeaders(sign,timestamp,requestId),requestBody);
    }

    /**
     * 获取头信息
     */
    private Map<String,String> getHeaders(String sign,Long timestamp,String requestId){
        Map<String,String> headerMap = new HashMap<>();
        headerMap.put("requestId", requestId);
        headerMap.put("sign",sign);
        headerMap.put("source", "3");
        headerMap.put("tenantCode", "");
        headerMap.put("timestamp",String.valueOf(timestamp));
        headerMap.put("version", "v0.1.0");
        headerMap.put("profile", "test");
        return headerMap;
    }

    /**
     * 将Map转换为application/x-www-form-urlencoded格式的请求体
     */
    private static String buildFormUrlBody(Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return "";
        }
        StringBuilder result = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (result.length() > 0) {
                result.append("&");
            }
            result.append(entry.getKey())
                    .append("=")
                    .append(entry.getValue());
        }
        return result.toString();
    }

    public static String convertToFormUrlEncoded(Object object) throws IllegalAccessException {
        if (object == null) {
            return "";
        }

        List<String> params = new ArrayList<>();
        Class<?> clazz = object.getClass();

        // 遍历对象的所有字段
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            Object value = field.get(object);

            // 忽略值为null的字段
            if (value != null) {
                String encodedName = URLEncoder.encode(field.getName(), StandardCharsets.UTF_8);
                String encodedValue = URLEncoder.encode(value.toString(), StandardCharsets.UTF_8);
                params.add(encodedName + "=" + encodedValue);
            }
        }
        return String.join("&", params);
    }

    /**
     * 生成签名数据
     * @param timestamp 时间戳（毫秒）
     * @param nonce     每次请求随机数（例如：d937ba2644854ec2949891a3ece94aca）
     * @return 签名数据
     */
    public static String generateSignature( Long timestamp, String nonce) {
        try {
            String tenantCode = "";
            String secret = "";
            // 构造待签名的字符串
            Map<String, String> params = new HashMap<>();
            params.put("appid", "");
            params.put("timestamp", String.valueOf(timestamp));
            params.put("nonce", nonce);
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            String signString = sb.substring(0, sb.length() - 1);

            // 使用HMAC-SHA256进行签名
            Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretKey);
            byte[] hash = sha256Hmac.doFinal(signString.getBytes(StandardCharsets.UTF_8));
            return Base64Utils.encodeToString(hash);
        } catch (Exception e) {

            throw new RuntimeException("Failed to generate signature", e);
        }
    }

    /**
     * 验证签名数据
     * @param appId     标记唯一第三方应用（企业唯一标识tenantCode）
     * @param secret    密钥（和签名时保持一致）
     * @param timestamp 时间戳（和签名时保持一致，毫秒）
     * @param nonce     每次请求随机数（和签名时保持一致）
     * @param clientSignature 客户端签名数据
     * @return true：验签成功，false:验证失败
     */
    public static Boolean verifySignature(String appId, String secret, Long timestamp, String nonce, String clientSignature) {
        try {
            // 构造待签名的字符串
            Map<String, String> params = new TreeMap<>();
            params.put("appid", appId);
            params.put("timestamp", String.valueOf(timestamp));
            params.put("nonce", nonce);
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            String signString = sb.substring(0, sb.length() - 1);

            // 使用HMAC-SHA256进行签名
            Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretKey);
            byte[] hash = sha256Hmac.doFinal(signString.getBytes(StandardCharsets.UTF_8));
            String serverSignature = Base64Utils.encodeToString(hash);
            return serverSignature.equals(clientSignature);
        } catch (Exception e) {
            throw new RuntimeException("Failed to verify signature", e);
        }
    }

}
